/**
  ******************************************************************************
  * @file    Project/ee_drivers/i2c.c
  * @version V 0.2
  * @date    20-MAY-2013
  * @author - Robert.Zhang<armner@gmail.com>
  * @brief   This file provides a set of functions needed to manage the
  *          communication between I2C peripheral and I2C M24CXX EEPROM.
             CAT5137 added,share the I2C.
  ******************************************************************************
*/

#include "stm32f2xx.h"

#define	I2C_delay()   delay_01us(200);
#define I2C_GROUP  (GPIOB)
#define I2C_PIN_SCL  (GPIO_Pin_6)
#define I2C_PIN_SDA  (GPIO_Pin_7)
#define I2C_GPIO_CLK    (RCC_AHB1Periph_GPIOB )

#define SCL_H         do{I2C_GROUP->BSRRL = I2C_PIN_SCL;}while(0)
#define SCL_L         do{I2C_GROUP->BSRRH  = I2C_PIN_SCL;}while(0)
#define SDA_H         do{I2C_GROUP->BSRRL = I2C_PIN_SDA;}while(0)
#define SDA_L         do{I2C_GROUP->BSRRH  = I2C_PIN_SDA;}while(0)
#define SCL_read      (I2C_GROUP->IDR  & I2C_PIN_SCL)
#define SDA_read      (I2C_GROUP->IDR  & I2C_PIN_SDA)

void delaysInit(void)
{
  // Timer13
    //get system clocks
    RCC_ClocksTypeDef RCC_Clocks;
        
    RCC_GetClocksFreq( &RCC_Clocks);

    RCC->APB1ENR |= RCC_APB1ENR_TIM13EN;           // Enable clock
    TIM13->PSC = (RCC_Clocks.PCLK1_Frequency * 2) / 10000000 - 1;      // 0.1uS 
    TIM13->CCER = 0;
    TIM13->CCMR1 = 0;
    TIM13->CR1 = 0x02;
    TIM13->DIER = 0;
}
	
void delay_01us(uint16_t nb)
{
    TIM13->EGR = 1;
    TIM13->CNT = 0;
    TIM13->CR1 = 0x03;
    while(TIM13->CNT < nb);
    TIM13->CR1 = 0x02;
}

/**
  * @brief  Configure the used I/O ports pin
  * @param  None
  * @retval None
  */
static void I2C_GPIO_Configuration(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  SDA_H;
  SCL_H;
  /* Configure I2C_EE pins: SCL and SDA */
  GPIO_InitStructure.GPIO_Pin =  I2C_PIN_SCL | I2C_PIN_SDA;//PE0,PE1
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(I2C_GROUP, &GPIO_InitStructure);
  
  //Set Idle levels
  SDA_H;
  SCL_H;
}

short I2C_Start()
{
  SDA_H;
  I2C_delay();
  SCL_H;
  I2C_delay();
  // if (!SDA_read) return 0;
  SDA_L;
  I2C_delay();
  // if (SDA_read) return 0;
  SCL_L;
  I2C_delay();
  return 1;
}

void I2C_Stop()
{
  SCL_L;
  I2C_delay();
  SDA_L;
  I2C_delay();
  SCL_H;
  I2C_delay();
  SDA_H;
  I2C_delay();
}

void I2C_ACK()
{
  SCL_L;
  I2C_delay();
  SDA_L;
  I2C_delay();
  SCL_H;
  I2C_delay();
  SCL_L;
  I2C_delay();
}
void I2C_NO_ACK()
{
  SCL_L;
  I2C_delay();
  SDA_H;
  I2C_delay();
  SCL_H;
  I2C_delay();
  SCL_L;
  I2C_delay();
}

short I2C_WAIT_ACK()
{
  short i=50;
  SCL_L;
  I2C_delay();
  SDA_H;
  I2C_delay();
  SCL_H;
  I2C_delay();
  while(i) {
    if(SDA_read) {
      I2C_delay();
      i--;
    }
    else {
      i=2;
      break;
    }
  }
  SCL_L;
  I2C_delay();

  return i;
} 

void I2C_Write(char *buffer)
{
    char SendByte =*buffer;
    short i=8;
    while (i--) {
        SCL_L;
        // I2C_delay();
        if (SendByte & 0x80)
            SDA_H;
        else
            SDA_L;
        SendByte <<= 1;
        I2C_delay();
        SCL_H;
        I2C_delay();
    }
    SCL_L;
    I2C_delay();
}

void I2C_Read( char *buffer)
{ 
    short i=8;
    char ReceiveByte=0;

    SDA_H;
    while (i--) {
        ReceiveByte <<= 1;
        SCL_L;
        I2C_delay();
        SCL_H;
        I2C_delay();
        if (SDA_read) {
            ReceiveByte|=0x01;
        }
    }
    SCL_L;
  
    *buffer = ReceiveByte;
} 

void I2C_Init()
{
    delaysInit();
    /* GPIO Periph clock enable */
    RCC_AHB1PeriphClockCmd(I2C_GPIO_CLK, ENABLE);

    /* GPIO configuration */
    I2C_GPIO_Configuration();
}

/*

void I2C_set_volume( register uint8_t volume )
{
  I2C_START();
  I2C_SEND_DATA(I2C_CAT5137_ADDRESS|EE_CMD_WRITE);
  I2C_WAIT_ACK();
  I2C_SEND_DATA(0);
  I2C_WAIT_ACK();
  I2C_SEND_DATA(volume);
  I2C_WAIT_ACK();
  I2C_STOP();
}

uint8_t I2C_read_volume()
{
  uint8_t volume ;
  I2C_START();
  I2C_SEND_DATA(I2C_CAT5137_ADDRESS|EE_CMD_WRITE);
  I2C_WAIT_ACK();
  I2C_SEND_DATA(0);
  I2C_WAIT_ACK();
  I2C_START();
  I2C_SEND_DATA(I2C_CAT5137_ADDRESS|EE_CMD_READ);
  I2C_WAIT_ACK();
  volume = I2C_READ();
  I2C_NO_ACK();
  I2C_STOP();
  return volume ;
}
*/